import gdata.apps.groups.service
import gdata.apps.service
import logging

import gaesessions

from glp.users.user import User
from google.appengine.api import users
from glp.users import user, login, session

# TODO(sdd): Make a way to dump user list

audience_group_ids = (
    'ops-administrators',
    'ops-learners',
    'ops-parents',
    'ops-policymakers',
    'ops-teacher-educators',
    'ops-teacher-learners',
    'ops-teachers')
discussion_group_ids = (
    'administrators-general',
    'everyone-general',
    'parents-general',
    'policymakers-general',
    'teacher-educators-general',
    'teacher-learners-general',
    'teachers-general')
role_to_group_id = {
    'policymaker' : 'ops-policymakers',
    'administrator' : 'ops-administrators',
    'teacher' : 'ops-teacher-educators',
    'parent' : 'ops-parents',
    'student' : 'ops-teacher-learners',
    'adult-learner' : 'ops-learners',
    'other' : 'ops-learners' }

def RecordRegistration(user, registration_id):
    user.email = users.get_current_user().email()
    user.registration_id = registration_id
    user.confirmed = False
    user.put()

def GetPendingRegistration(email):
    registrations = User.all().filter('email =', email).filter('confirmed =', False).fetch(2)
    if len(registrations) != 1: return None
    return registrations[0]

def ConfirmRegistration(id):
    registrations = User.all().filter('registration_id =', id).filter('confirmed =', False).fetch(2)
    if len(registrations) != 1: return None
    registration = registrations[0]
    registration.confirmed = True
    registration.put()
    return registration

def GetUsers():
    return User.all()

def GetUser(email):
    users = User.all().filter('email =', email).filter('confirmed =', True).fetch(2)
    if len(users) != 1: return None
    return users[0]

def GetGroupService(authenticator):
    return authenticator.CreateClient(
        gdata.apps.groups.service.GroupsService().__class__,
        'https://apps-apis.google.com/a/feeds/group/2.0/educationcommons.rw',
        'educationcommons.rw', 'admin.robot')

def UpdateGroups(authenticator, email):
    if not email: raise AttributeException('email required')
    logging.info('Updating groups for %s...' % email)
    user = GetUser(email)
    if not user: raise LookupError('unknown user: %s' % email)
    group_add_id = role_to_group_id[user.role]
    service = GetGroupService(authenticator)
    if not service: return False
    logging.info('Adding %s to %s...' % (email, group_add_id))
    service.AddMemberToGroup(user.email, group_add_id)
    for group_id in audience_group_ids:
        if group_id == group_add_id: continue
        try:
            service.RemoveMemberFromGroup(user.email, group_id)
            logging.info("%s removed from %s" % (user.email, group_id))
        except gdata.apps.service.AppsForYourDomainException:
            logging.info("%s was not a member of %s" % (user.email, group_id))
    for group_id in discussion_group_ids:
        logging.info('Adding %s to %s...' % (email, group_id))
        service.AddMemberToGroup(user.email, group_id)
    logging.info('Done updating groups for %s.' % email)
    return True

def ComputeGroupRebuildingTasks(authenticator):
    current_members = {}
    members = {}
    for group_id in discussion_group_ids + audience_group_ids:
        current_members[group_id] = set()
        members[group_id] = set()
    logging.info("Scanning users for community affiliations...")
    for user in User.all():
        if not user.confirmed: continue
        email = user.email.lower().replace("googlemail.com", "gmail.com")
        audience_group_id = role_to_group_id[user.role]
        members[audience_group_id].add(email)
        for group_id in discussion_group_ids:
            members[group_id].add(email)
    tasks = []
    logging.info("Scanning groups for current memberships and calculating tasks...")
    service = GetGroupService(authenticator)
    if not service: return None
    for group_id in discussion_group_ids + audience_group_ids:
        for member in service.RetrieveAllMembers(group_id, True):
            if not member['directMember']: continue
            if member['memberId'] == 'ops-owners@educationcommons.rw': continue
            current_members[group_id].add(member['memberId'].lower())
        logging.info(members[group_id])
        logging.info(current_members[group_id])
        for member_id in current_members[group_id] - members[group_id]:
            tasks.append(('remove', member_id, group_id, 'removal of %s from %s' % (member_id, group_id)))
        for member_id in members[group_id] - current_members[group_id]:
            tasks.append(('add', member_id, group_id, 'addition of %s to %s' % (member_id, group_id)))
    logging.info("Group rebuilding task computation complete.")
    return tasks

def RemoveUserFromGroup(authenticator, member_id, group_id):
    logging.info('Removing %s from %s...' % (member_id, group_id))
    service = GetGroupService(authenticator)
    if not service: return False
    try:
        service.RemoveMemberFromGroup(member_id, group_id)
    except:
        return False
    return True

def AddUserToGroup(authenticator, member_id, group_id):
    logging.info('Adding %s to %s...' % (member_id, group_id))
    service = GetGroupService(authenticator)
    if not service: return False
    service.AddMemberToGroup(member_id, group_id)
    return True

def LoginUser(user):
  session = gaesessions.get_current_session()
  if session.is_active():
    session.terminate()
  session['user'] = user

def LogoutCurrentUser():
  session = gaesessions.get_current_session()
  session.terminate()

# Note that the below naming is consistent with the appengine's users.py module
# which is why it doesn't follow the naming scheme of the rest of the module
def get_current_user():
  session = gaesessions.get_current_session()
  return session.get('user')

def create_logout_url(redirect_url):
  return '/users/logout?return=%s' % redirect_url

def create_login_url(
    redirect_url, federated_identity='https://www.google.com/accounts/o8/id'):
  return '/begin/?domain=%s&return=%s' % (federated_identity, redirect_url)
